package com.dsl.dslsuzhou.service;

import com.dsl.dslsuzhou.config.CameraConfig;
import com.dsl.dslsuzhou.model.dto.CameraPageResponse;
import com.dsl.dslsuzhou.model.dto.ThirdPartyApiResponse;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;

/**
 * 第三方摄像头接口调用服务
 */
@Slf4j
@Service
public class CameraThirdPartyService {
    
    @Autowired
    private CameraConfig cameraConfig;

    private WebClient webClient;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 初始化WebClient（不包含token，token在每次请求时动态添加）
     */
    private WebClient getWebClient() {
        if (webClient == null) {
            String baseUrl = cameraConfig.getThirdParty().getBaseUrl();
            log.info("初始化WebClient，baseUrl: {}", baseUrl);

            webClient = WebClient.builder()
                    .baseUrl(baseUrl)
                    .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json")
                    .defaultHeader(HttpHeaders.USER_AGENT, "Camera-Proxy-Service/1.0")
                    .build();
        }
        return webClient;
    }

    /**
     * 调用第三方分页接口
     */
    public Mono<CameraPageResponse> getCameraPage(Integer current, Integer size, List<String> devIds, Integer status, String token) {


        return callWithRetry(current, size, devIds, status, token, 0);
    }

    /**
     * 带重试的调用方法
     */
    private Mono<CameraPageResponse> callWithRetry(Integer current, Integer size, List<String> devIds, Integer status, String token, int attempt) {
        // 检查token是否为空
        if (!StringUtils.hasText(token)) {
            log.error("第三方接口Token为空");
            return Mono.error(new IllegalArgumentException("Token不能为空"));
        }

        String path = cameraConfig.getThirdParty().getCameraPagePath();

        return getWebClient()
                .get()
                .uri(uriBuilder -> {
                    uriBuilder.path(path)
                            .queryParam("current", current)
                            .queryParam("size", size);

                    // 添加devIds参数
                    if (devIds != null && !devIds.isEmpty()) {
                        String devIdsStr = String.join(",", devIds);
                        uriBuilder.queryParam("devIds", devIdsStr);
                        log.debug("添加devIds参数: {}", devIdsStr);
                    }

                    // 添加status参数（如果支持）
                    if (status != null) {
                        uriBuilder.queryParam("status", status);
                        log.debug("添加status参数: {}", status);
                    }

                    // 正确的URL日志记录（WebClient会自动拼接baseUrl）
                    String relativePath = uriBuilder.build().toString();
                    log.info("调用第三方接口路径: {}", relativePath);
                    log.info("请求头token: {}", token != null ? "***" + token.substring(Math.max(0, token.length() - 4)) : "null");

                    return uriBuilder.build();
                })
                .header("token", token)  // 使用传入的token
                .retrieve()
                .onStatus(HttpStatus::isError, response -> {
                    log.error("第三方接口返回错误状态: {}", response.statusCode());
                    return response.bodyToMono(String.class)
                            .doOnNext(body -> log.error("错误响应体: {}", body))
                            .then(Mono.error(new RuntimeException("第三方接口返回错误: " + response.statusCode())));
                })
                .bodyToMono(String.class)  // 先获取原始字符串
                .doOnNext(rawResponse -> {
                    log.info("第三方接口原始响应: {}", rawResponse != null ? rawResponse.substring(0, Math.min(500, rawResponse.length())) : "null");
                })
                .flatMap(rawResponse -> {
                    try {
                        // 检查响应是否为空
                        if (rawResponse == null || rawResponse.trim().isEmpty()) {
                            log.error("第三方接口返回空响应");
                            return Mono.error(new RuntimeException("第三方接口返回空响应"));
                        }

                        // 解析第三方接口的完整响应结构
                        TypeReference<ThirdPartyApiResponse<CameraPageResponse>> typeRef =
                            new TypeReference<ThirdPartyApiResponse<CameraPageResponse>>() {};
                        ThirdPartyApiResponse<CameraPageResponse> thirdPartyResponse =
                            objectMapper.readValue(rawResponse, typeRef);

                        log.info("第三方接口响应解析成功: code={}, message={}",
                                thirdPartyResponse.getCode(), thirdPartyResponse.getMessage());

                        // 检查响应码
                        if (thirdPartyResponse.getCode() != null && thirdPartyResponse.getCode() == 0) {
                            // 成功响应，返回data部分
                            CameraPageResponse pageResponse = thirdPartyResponse.getData();
                            if (pageResponse != null) {
                                log.info("解析成功: total={}, records={}",
                                        pageResponse.getTotal(),
                                        pageResponse.getRecords() != null ? pageResponse.getRecords().size() : 0);
                                return Mono.just(pageResponse);
                            } else {
                                log.warn("第三方接口data为空，返回默认响应");
                                return Mono.just(createDefaultResponse(current, size));
                            }
                        } else {
                            // 第三方接口返回业务错误
                            String errorMsg = "第三方接口业务错误: code=" + thirdPartyResponse.getCode() +
                                            ", message=" + thirdPartyResponse.getMessage();
                            log.error(errorMsg);
                            return Mono.error(new RuntimeException(errorMsg));
                        }

                    } catch (Exception e) {
                        log.error("解析第三方接口响应失败: {}, 原始响应: {}", e.getMessage(),
                                rawResponse.length() > 200 ? rawResponse.substring(0, 200) + "..." : rawResponse);
                        return Mono.error(new RuntimeException("解析响应失败: " + e.getMessage()));
                    }
                })
                .timeout(Duration.ofSeconds(cameraConfig.getThirdParty().getResponseTimeout()))
                .doOnSuccess(response -> log.info("第三方接口调用成功: total={}",
                        response != null ? response.getTotal() : 0))
                .doOnError(error -> {
                    log.error("第三方接口调用失败，尝试次数: {}, 错误类型: {}, 错误信息: {}",
                            attempt + 1, error.getClass().getSimpleName(), error.getMessage());
                    if (error.getCause() != null) {
                        log.error("根本原因: {}", error.getCause().getMessage());
                    }
                })
                .onErrorResume(throwable -> {
                    // 判断是否需要重试
                    if (shouldRetry(throwable) && attempt < cameraConfig.getRetry().getMaxAttempts() - 1) {
                        long delay = (long) (cameraConfig.getRetry().getInitialInterval() * Math.pow(cameraConfig.getRetry().getMultiplier(), attempt));
                        log.info("第{}次调用失败，{}ms后重试", attempt + 1, delay);
                        return Mono.delay(Duration.ofMillis(delay))
                                .then(callWithRetry(current, size, devIds, status, token, attempt + 1));
                    } else {
                        return handleError(throwable);
                    }
                });
    }
    
    /**
     * 错误处理方法
     */
    private Mono<CameraPageResponse> handleError(Throwable ex) {
        log.error("摄像头接口调用失败: {}", ex.getMessage());

        // 对于5xx错误，返回错误；对于其他错误，返回空结果
        if (ex instanceof WebClientResponseException) {
            WebClientResponseException webEx = (WebClientResponseException) ex;
            if (webEx.getStatusCode().is5xxServerError()) {
                return Mono.error(ex);
            }
        }

        // 返回空结果
        CameraPageResponse response = new CameraPageResponse();
        response.setRecords(new ArrayList<>());
        response.setTotal(0L);
        response.setPages(0L);
        response.setCurrent(1L);
        response.setSize(10L);

        return Mono.just(response);
    }
    
    /**
     * 检查异常类型，判断是否需要重试
     */
    private boolean shouldRetry(Throwable ex) {
        if (ex instanceof WebClientResponseException) {
            WebClientResponseException webEx = (WebClientResponseException) ex;
            HttpStatus status = webEx.getStatusCode();
            // 5xx错误或超时错误才重试
            return status.is5xxServerError();
        }

        // 超时异常重试
        return ex instanceof TimeoutException;
    }

    /**
     * 创建默认响应
     */
    private CameraPageResponse createDefaultResponse(Integer current, Integer size) {
        CameraPageResponse response = new CameraPageResponse();
        response.setTotal(0L);
        response.setPages(0L);
        response.setCurrent(current.longValue());
        response.setSize(size.longValue());
        response.setRecords(new java.util.ArrayList<>());
        return response;
    }


}
